import { isArray, isNumber, isObject, isString } from "../utils/utility"

// 为了快速判断节点类型，给每个类型定义枚举值
// 使用&运算即可快速判断
export const ShapeFlags = {
    ELEMENT: 1, // 0000 0001
    TEXT: 1 << 1,  // 0000 0010
    FRAGMENT: 1 << 2,  // 0000 0100
    COMPONENT: 1 << 3, // 0000 1000
    TEXT_CHILDREN: 1 << 4, // 0001 0000
    ARRAY_CHILDREN: 1 << 5, // 0010 0000
    CHILDREN: (1 << 4) | (1 << 5) // 0011 0000
}

export const Text = Symbol("Text")

// Fragment是框架，本身不会被渲染，只有其子节点会被渲染
export const Fragment = Symbol("Fragment")


/**
 * @description: 生成一个VNode
 * @param {string | Object | Text | Fragment} type
 * @param {Object | null} props
 * @param {string | number | Array | null} children
 * @return {VNode}
 */
export function h(type, props, children) {
    let shapeFlag = 0
    if (isString(type)) {
        shapeFlag = ShapeFlags.ELEMENT
    } else if (type === Text) {
        shapeFlag = ShapeFlags.TEXT
    } else if (type === Fragment) {
        shapeFlag = ShapeFlags.FRAGMENT
    } else {
        shapeFlag = ShapeFlags.COMPONENT
    }

    if (isString(children) || isNumber(children)) {
        shapeFlag |= ShapeFlags.TEXT_CHILDREN
        children = children.toString()
    } else if (isArray(children)) {
        shapeFlag |= ShapeFlags.ARRAY_CHILDREN
    }

    return {
        type,
        props,
        children,
        shapeFlag,
        el: null,    // 所在节点
        anchor: null,    // 仅作用于Fragment，确定元素锚点
        key: props && props.key, // 专门用于更新DOM
        component: null // 专门用于存储组件的实例
    }
}

/**
 * @description: 将render函数返回值转为有效的vnode
 * @param {string | number | Array | function } result
 * @return {VNode}
 */
export function normalizeVNode(result) {
    if (isArray(result)) {
        return h(Fragment, null, result)
    } else if (isObject(result)) {
        return result
    }

    return h(Text, null, result.toString())
}